package flyweight

import (
	"fmt"
	"strconv"
	"sync"
)

// CharacterStyle 内部状态 可共享
type CharacterStyle struct {
	FontFamily string
	FontSize   int
	Color      string
	IsBold     bool
	IsItalic   bool
}

func (s *CharacterStyle) String(content string) string {
	return fmt.Sprintf("Font: %s, FontSize: %d, Color: %s, Bold: %t, Italic: %t, Content: %s",
		s.FontFamily, s.FontSize, s.Color, s.IsBold, s.IsItalic, content)
}

// CharacterFlyweight 享元接口
type CharacterFlyweight interface {
	Render(positionX, positionY int, char rune) string
}

// Character 具体享元
type Character struct {
	style *CharacterStyle
}

func NewCharacter(style *CharacterStyle) *Character {
	return &Character{
		style: style,
	}
}

func (c *Character) Render(positionX, positionY int, char rune) string {
	return fmt.Sprintf("渲染字符 '%c' 在位置 (%d, %d) 使用样式: %s",
		char, positionX, positionY, c.style.String(string(char)))
}

// CharacterStyleFactory 享元工厂
type CharacterStyleFactory struct {
	styles map[string]*CharacterStyle
	mutex  sync.Mutex
}

var styleFactory *CharacterStyleFactory

func GetCharacterStyleFactory() *CharacterStyleFactory {
	if styleFactory == nil {
		styleFactory = &CharacterStyleFactory{
			styles: make(map[string]*CharacterStyle),
		}
	}
	return styleFactory
}

func (f *CharacterStyleFactory) GetStyle(fontFamily string, fontSize int, color string, bold, italic bool) *CharacterStyle {
	key := f.generateKey(fontFamily, fontSize, color, bold, italic)
	f.mutex.Lock()
	defer f.mutex.Unlock()
	if style, ok := f.styles[key]; ok {
		return style
	}
	style := &CharacterStyle{
		FontFamily: fontFamily,
		FontSize:   fontSize,
		Color:      color,
		IsBold:     bold,
		IsItalic:   italic,
	}
	f.styles[key] = style
	return style
}

func (f *CharacterStyleFactory) generateKey(fontFamily string, fontSize int, color string, bold, italic bool) string {
	return fontFamily + "-" + strconv.Itoa(fontSize) + "-" + color + "-" + strconv.FormatBool(bold) + "-" + strconv.FormatBool(italic)
}

func (f *CharacterStyleFactory) TotalStyles() int {
	return len(f.styles)
}

// DocumentCharacter 文档中的字符
type DocumentCharacter struct {
	char      rune
	positionX int
	positionY int
	flyweight CharacterFlyweight
}

func NewDocumentCharacter(char rune, x, y int, style *CharacterStyle) *DocumentCharacter {
	return &DocumentCharacter{
		char:      char,
		positionX: x,
		positionY: y,
		flyweight: NewCharacter(style),
	}
}

func (dc *DocumentCharacter) Render() string {
	return dc.flyweight.Render(dc.positionX, dc.positionY, dc.char)
}

// ========= 文档 =========
type Document struct {
	characters []*DocumentCharacter
}

func (d *Document) AddCharacter(char rune, x, y int, fontFamily string, fontSize int, color string, bold, italic bool) {
	style := GetCharacterStyleFactory().GetStyle(fontFamily, fontSize, color, bold, italic)
	dc := NewDocumentCharacter(char, x, y, style)
	d.characters = append(d.characters, dc)
}

func (d *Document) Render() {
	for _, char := range d.characters {
		fmt.Println(char.Render())
	}
}

func (d *Document) TotalCharacters() int {
	return len(d.characters)
}
